Skip to content

fix(web): render local images inline - #5114

Closed
berend wants to merge 12 commits into
pingdotgg:mainfrom
berend:fix/local-markdown-images
Closed

fix(web): render local images inline#5114
berend wants to merge 12 commits into
pingdotgg:mainfrom
berend:fix/local-markdown-images

Conversation

@berend

@berend berend commented Jul 31, 2026

Copy link
Copy Markdown

Problem

Local workspace images referenced in chat Markdown render as broken placeholders, even though the same paths work as file links. Image generation and view_image also provide local paths that were not surfaced as visible image output.

Fixes #2398.

Fix

  • Resolve supported relative, absolute, and file:// workspace image sources through T3 Code's existing signed asset URLs.
  • Preserve Codex imageGeneration.savedPath and imageView.path lifecycle data and render those outputs inline in the work log.
  • Keep remote image rendering and existing workspace file-link behavior unchanged.
  • Add focused coverage for Markdown image resolution, Codex lifecycle mapping, and web work-log derivation.

This reuses the existing workspace asset boundary: paths are resolved against the thread workspace and served through expiring signed URLs instead of exposing raw local-file URLs.

Screenshots

The screenshots for generated image output and workspace images rendered through Markdown were captured with a local development build and will be attached separately.

Validation

  • pnpm exec vp test run apps/web/src/markdown-links.test.ts apps/web/src/session-logic.test.ts apps/server/src/provider/Layers/CodexAdapter.test.ts — 122 tests passed
  • pnpm exec vp run --filter @t3tools/web typecheck
  • pnpm exec vp run --filter t3 typecheck
  • Manual local development build verification for relative Markdown images, file links, remote images, Codex image generation, and view_image
display_via_markdown render_image

you can see the before in the linked issue

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included screenshots for the UI changes
  • A video is not applicable because there are no animation or interaction changes

🤖 Implementation and tests were generated with OpenAI Codex (GPT-5.6 Sol) through the T3 Code Codex harness, then reviewed and verified in a local development build.


Note

Low Risk
UI and asset-display changes reusing the existing signed workspace-file boundary; no auth or persistence changes.

Overview
Fixes broken local image placeholders by routing workspace image paths through the existing signed asset URL flow instead of raw file: URLs.

Chat Markdown adds resolveMarkdownImageFileLinkMeta and a MarkdownWorkspaceImage component that resolves relative, absolute, and file:// image sources against the thread workspace. The sanitize schema now allows file: on img src; remote images are unchanged.

Work log derives an imagePath on image_view entries from Codex savedPath/path, Claude file lists, and image-like details, then renders inline previews under the row via ChatMarkdown. Server keeps savedPath in activity payload projection and maps Codex savedPath into lifecycle detail.

Clipboard stores the original markdown source on data-markdown-src so copy/paste round-trips workspace paths (including encoded Windows paths) rather than expiring signed URLs.

Reviewed by Cursor Bugbot for commit b9f2090. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render local workspace images inline in chat work log entries

  • Adds MarkdownWorkspaceImage component in ChatMarkdown.tsx that resolves workspace file paths to signed asset URLs and renders them inline, with loading/error fallbacks.
  • Extends SimpleWorkEntryRow in MessagesTimeline.tsx to display an inline image when workEntry.imagePath is set and a threadRef is available.
  • Adds imagePath to WorkLogEntry in session-logic.ts, derived from item.savedPath, item.path, changedFiles, or payload.detail for image_view activities.
  • Updates clipboard serialization in markdown-clipboard.ts to use the original markdown source (via data-markdown-src) rather than signed URLs when copying images.
  • Extends ActivityPayloadProjection to retain savedPath through payload projection so image paths survive to the frontend.

Macroscope summarized b9f2090.

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7fecf021-ec36-42ce-b75f-43b542d582e9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 31, 2026
Comment thread apps/web/src/session-logic.ts
@macroscopeapp

macroscopeapp Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new feature enabling inline rendering of local workspace images. It adds new user-facing behavior with a new component that fetches signed asset URLs, touches multiple layers (server projection, web rendering, clipboard handling), and warrants human review to verify the integration across these components.

You can customize Macroscope's approvability policy. Learn more.

Use the preserved activity detail when nested provider image data is removed during transport projection. Add regression coverage for the projected production payload shape.

Addresses pingdotgg#5114 (comment)

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
Comment thread apps/web/src/session-logic.ts
Comment thread apps/web/src/session-logic.ts Outdated
Reject non-path image detail summaries and recover projected structured image paths before rendering. Preserve original Markdown image sources when copying so signed asset URLs do not leave the app.

Addresses pingdotgg#5114 (comment)

Addresses pingdotgg#5114 (comment)

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 31, 2026
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
berend and others added 2 commits August 1, 2026 16:53
Add integration coverage for the existing Windows work-log image path flow. This changes no production behavior; it confirms that Markdown URL sanitization already preserves the decoded path for signed asset requests.

Documents pingdotgg#5114 (comment) as a false positive.

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
berend and others added 2 commits August 1, 2026 22:59
Add clipboard coverage proving that percent-encoded Windows image paths resolve back to the original workspace path. This changes no production behavior and confirms the copied Markdown remains functional.

Documents pingdotgg#5114 (comment) as a false positive.

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol

karimou5 commented Aug 2, 2026

Copy link
Copy Markdown

Tested this PR locally and it fixed the issue for me.

Environment: Ubuntu 24.04.4 LTS (Debian-based), x86_64, kernel 7.0.0-28-generic, T3 Code AppImage. I built PR head c0559ff together with an unrelated local preview screenshot patch.

Both local Markdown images and view_image output now render inline correctly. The targeted test suite also passed: 218 tests.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3ec9e15. Configure here.

Comment thread apps/web/src/session-logic.ts
Preserve structured savedPath values in projected item data so generated images still render when the human-readable activity detail is truncated.

Addresses pingdotgg#5114 (comment)

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
@Kastango

Copy link
Copy Markdown

up

sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 20, 2026
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 20, 2026
Both are fallout from resolving this sync's conflicts, caught by tsc rather
than by a test.

ChatMarkdown had two `img` handlers after the pingdotgg#5114 merge: upstream's, which
exists only to drop the native `title` attribute, and the pull request's, which
resolves a workspace image path. Merged into one that does both.

ChatComposer lost the `getProviderDisplayName` import when the plan usage
commit's import hunk was resolved in upstream's favour, while the call site it
feeds survived.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit d96437f909c1ff8e6c26a02ce80cbb8511dad51e)
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 20, 2026
All four are fallout from replaying the carried set onto 50 new upstream
commits, caught by tsgo and the targeted suites rather than by the merge.

The settled preview reaper passed `changeRequestState` to `effectiveSettled`,
which upstream renamed to `changeRequest`. The traits picker's own test grew
upstream's required `planModeEnabled` input, since the fork's
`excludeDescriptorIds` parameter now sits beside it rather than in its place.

Two tests describe behaviour upstream changed underneath them. pingdotgg#7152 folds a
tool-only work group behind a "+N tool calls" toggle and keeps only the last
entry of a group visible, so the pingdotgg#5114 image row assertion was reading a
collapsed group; the entry now sits last in a mixed group, which is the shape
that renders it inline. pingdotgg#7252 mutes browser tabs on attach, so the fork's
hand-rolled fake webContents needs `setAudioMuted` and `isCurrentlyAudible`
like upstream's shared fake already has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@berend

berend commented Aug 20, 2026

Copy link
Copy Markdown
Author

Hi there,
looks like T3Code is not merging any PRs from external people currently - which is fine.

I will stop updating to upstream until get I a go.

Local images still dont render as I am writing this. Not a big deal, but would be nice to have.

@maintainers: feel free to close this, if it is not needed anymore, I wont have any hard feelings about this

Peace, nerds!

sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 20, 2026
Both go in the Fixes table ahead of the build, so the fork overview ships
current. No change to the carried pull requests: pingdotgg#4989 and pingdotgg#5114 are both still
open upstream as of today, and pingdotgg#5114's head is still the pinned b9f2090.

Written by Claude Opus 5 in T3 Code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 23, 2026
…for upstream's

Upstream merged pingdotgg#6433 today, its own implementation of inline workspace
images in chat markdown, on both web and mobile. That collided with the
carried pingdotgg#5114 renderer in the one place it could not be seen: both defined
an `img` key in the same `markdownComponents` object literal, so upstream's
silently won at runtime and the fork's became dead code. Only `tsgo` noticed,
as a duplicate identifier.

Removes the fork's `img` handler, its `MarkdownWorkspaceImage` component and
a duplicated `useAssetUrlState` import. Upstream's `ChatMarkdownWorkspaceImage`
is now the only path, and its own six tests cover it.

The work-log half of pingdotgg#5114 is NOT superseded and stays: `session-logic` still
uses `resolveMarkdownImageFileLinkMeta` to surface a generated or changed image
as its own activity row, which upstream does not do.
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 23, 2026
@t3dotgg

t3dotgg commented Aug 23, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Workspace image rendering already shipped in #6433.

@t3dotgg t3dotgg closed this Aug 23, 2026
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 29, 2026
New upstream base, the palette fleet spawn in the Interface table, pingdotgg#5114 now
closed upstream without merging, and the chat anchor row updated for upstream
pingdotgg#7971 landing a mid-turn release that does not cover the settle case.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Codex image generation support

4 participants